/*
 * 
 *  $Author: nfelipe$
 * 
 *  Copyright (c) 2011 by PROS Revenue Management.  All Rights Reserved.
 *  This software is the confidential and proprietary information of
 *  PROS Revenue Management ("Confidential Information").
 *  You shall not disclose such Confidential Information and shall use it
 *  only in accordance with the terms of the license agreement you entered
 *  into with PROS.
 * 
 */

package javaapplication2;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.awt.image.ByteLookupTable;
import java.awt.image.LookupOp;
import java.awt.image.Raster;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.imageio.ImageIO;

/**
 *
 * @author Nestor Felipe
 */
public class get_changed_region {
    
    public static boolean are_equals(BufferedImage image1, BufferedImage image2){

        Raster r1 = image1.getData();
        Raster r2 = image2.getData();
        boolean ret; // Stores result.

        // Check image sizes and number of bands.  If there are different
        // then no need to compare images as they are definitely not equal.
        if (r1.getNumBands() != r2.getNumBands() ||
          r1.getWidth() != r2.getWidth() ||
          r1.getHeight() != r2.getHeight()) {
          ret = false;
        } else {
          // #Bands and image bounds match so compare each sample in turn.

          ret = true;

          search:
          for (int i=0; i<r1.getNumBands(); ++i) {
            for (int x=0; x<r1.getWidth(); ++x) {
              for (int y=0; y<r1.getHeight(); ++y) {
                if (r1.getSample(x, y, i) != r2.getSample(x, y, i)) {
                  // At least one sample differs so result is false;
                  ret = false;
                  // Use labeled break to terminate all loops.
                  break search;
                }
              }
            }
          }

        }
        return ret;
    }

    public static BufferedImage negative(BufferedImage img) {
        Color col;
        for (int x = 0; x < img.getWidth(); x++) { //width
            for (int y = 0; y < img.getHeight(); y++) { //height
                    
                int RGBA  = img.getRGB(x, y); //gets RGBA data for the specific pixel

                col = new Color(RGBA, true); //get the color data of the specific pixel

                if(x == 77 && y == 77){
                    print_rgb_values("Original", col);
                }
                col = new Color(255 - col.getRed(), 255 - col.getGreen(), 255 - col.getBlue()); //Swaps values
                //i.e. 255, 255, 255 (white)
                //becomes 0, 0, 0 (black)
                
                if(x == 77 && y == 77){
                    print_rgb_values("Inverted", col);
                }

                img.setRGB(x, y, col.getRGB()); //set the pixel to the altered colors
            }
        }
        return img;
    }

//    public static BufferedImage negative(BufferedImage bimg) {
//        int height = bimg.getHeight();
//        int width  = bimg.getWidth();
//
//        BufferedImage buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
//
//       byte reverse[] = new byte[256];
//       for (int j=0; j<256; j++){
//                    reverse[j]=(byte)(256-j);
//            }
//            ByteLookupTable blut=new ByteLookupTable(0, reverse);
//            LookupOp lop = new LookupOp(blut, null);
//       lop.filter(bimg,buffer);
//       return buffer;
//    }

    public static BufferedImage overlayImage(BufferedImage original, BufferedImage changed){
        int height = original.getHeight();
        int width  = original.getWidth();
        
        Color original_color;
        Color changed_color;
        Color color_merged;
        BufferedImage buffer_combined = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        
        // paint both images, preserving the alpha channels
//        Graphics2D g = buffer_combined.createGraphics();
//        g.drawImage(image2, image1, 0, 0);
//        g.drawImage(image1, 0, 0, null);
        
        for (int x = 0; x < buffer_combined.getWidth(); x++) { //width
            for (int y = 0; y < buffer_combined.getHeight(); y++) { //height

                int RGBA_img1 = original.getRGB(x, y); //gets RGBA data for the specific pixel
                int RGBA_img2 = changed.getRGB(x, y);

                original_color = new Color(RGBA_img1, true); //get the color data of the specific pixel
                changed_color  = new Color(RGBA_img2, true);

                if(x == 77 && y == 77){
                    print_rgb_values(" first color", original_color);
                    print_rgb_values("second color", changed_color);
                }
//                color_merged = new Color(Math.abs(col1.getRed() - col2.getRed()),
//                        Math.abs(col1.getGreen() - col2.getGreen()), Math.abs(col1.getBlue() - col2.getBlue())); //Swaps values
                color_merged = new Color(255, 255, 255);
                try{
                    color_merged = original_color.equals(changed_color)? new Color(255,255,255): new Color(0,0,0);
                    
                } catch(Exception e){
                    System.out.println("(" + x + ", "  + y + ")");
                    print_rgb_values("Error color 1", original_color);
                    print_rgb_values("Error color 2", changed_color);
                }
                //i.e. 255, 255, 255 (white)
                //becomes 0, 0, 0 (black)
                if(x == 77 && y == 77){
                    print_rgb_values("merged color", color_merged);
                }
                buffer_combined.setRGB(x, y, color_merged.getRGB()); //set the pixel to the altered colors
            }
        }
//        g.dispose();
        return buffer_combined;
    }
    public static Color rectified_colors(Color col1, Color col2){
        
        int red_color   = (col2.getRed() + col1.getRed());
        int green_color = (col2.getGreen() + col1.getGreen());
        int blue_color  = (col2.getBlue() + col1.getBlue());
        
        Color res = red_color == 255 && green_color == 255 && blue_color == 255? new Color(255, 255, 255): col1;
        return res;
    }
    
    public static void print_rgb_values(String msg, Color col){
        System.out.println(msg + ": (" + col.getRed() + ", "
                                       + col.getGreen() + ", "
                                       + col.getBlue() + ")");
    }

    public static boolean[][] createBooleanMatrix(BufferedImage original, BufferedImage changed){
        
        Color original_color;
        Color changed_color;
        
        int height = original.getHeight();
        int width  = original.getWidth();
        
        boolean[][] matrix = new boolean[width][height];

        for (int x = 0; x < original.getWidth(); x++) { //width
            for (int y = 0; y < original.getHeight(); y++) { //height

                int RGBA_img1 = original.getRGB(x, y); //gets RGBA data for the specific pixel
                int RGBA_img2 = changed.getRGB(x, y);

                original_color = new Color(RGBA_img1, true); //get the color data of the specific pixel
                changed_color  = new Color(RGBA_img2, true);

                matrix[x][y] = original_color.equals(changed_color)? false: true;
            }
        }

        return matrix;
    }

    public static Pixel getStartPoint(boolean[][] matrix){

        for (int x = 0; x < matrix.length; x++) { //width or row
            for (int y = 0; y < matrix[x].length; y++) { //height or col

                if (matrix[x][y]){
                    return new Pixel(x, y);
                }
            }
        }
        return null;
    }

    public static RegionPosition getFirstBooleanShape(boolean[][] matrix){

        Pixel start_point  = getStartPoint(matrix);

        RegionPosition shape = new RegionPosition();
        
        walk(start_point, matrix, shape);

        return shape;
    }

    public static void walk(Pixel current_pixel, boolean[][] matrix, RegionPosition shape_result){
        int x = current_pixel.getX();
        int y = current_pixel.getY();
        
        if(current_pixel.isNegative() || x >= matrix.length || y >= matrix[x].length)
            return;
        
        if(matrix[x][y]){
            try{
                shape_result.add(current_pixel);
            }catch(Exception e){
                System.out.println("");
            }

            // All pixel arount the current pixel
            Pixel[] around = new Pixel[8];
            around[0] = new Pixel(current_pixel.getX() -1, current_pixel.getY() -1);
            around[1] = new Pixel(current_pixel.getX() +0, current_pixel.getY() -1);
            around[2] = new Pixel(current_pixel.getX() +1, current_pixel.getY() -1);
            around[3] = new Pixel(current_pixel.getX() +1, current_pixel.getY() +0);
            around[4] = new Pixel(current_pixel.getX() +1, current_pixel.getY() +1);
            around[5] = new Pixel(current_pixel.getX() +0, current_pixel.getY() +1);
            around[6] = new Pixel(current_pixel.getX() -1, current_pixel.getY() +1);
            around[7] = new Pixel(current_pixel.getX() -1, current_pixel.getY() +0);

            for(int i = 0; i < around.length; i++){
                walk(around[i], matrix, shape_result);
            }
        }
    }

    public static Pixel getChangedRegion(BufferedImage original, BufferedImage changed){

        int left, rigth, top, down;
        left = rigth = top = down = 0;
        
        Color original_color;
        Color changed_color;
        
        int height = original.getHeight();
        int width  = original.getWidth();
        
        
        boolean[][] matrix = createBooleanMatrix(original, changed);

        RegionPosition shape = getFirstBooleanShape(matrix);

        System.out.println(shape.toString());
        
        return new Pixel();
    }
    
    public static void showCollection(List<Pixel> list){
        Iterator<Pixel> itr = list.iterator();
        Pixel current = null;

        while(itr.hasNext()){
            current = itr.next();
            System.out.println("x = " + current.getX() + ", y = " + current.getY());
        }
        
    }
    
    public static void main(String arg[]) throws IOException{
        get_changed_region c = new get_changed_region();
        
        File inputfile = new File("screen.png");
        File inputfile2 = new File("screen2.png");
        BufferedImage b1 = ImageIO.read(inputfile);
        BufferedImage b2 = ImageIO.read(inputfile2);

//        System.out.println("result: " + Compare_Images.are_equals(b1, b2));

//        BufferedImage b1neg = negative(b1);
//        File outputfile = new File("b2Neg.png");
//        ImageIO.write(b1neg, "png", outputfile);

//        BufferedImage overlaped = overlayImage(b1, b2);
//        File overlapFile = new File("overlap.png");
//        ImageIO.write(overlaped, "png", overlapFile);
        
        Pixel overlaped = getChangedRegion(b1, b2);
        
    }
}


class RegionPosition{
    int x_max, x_min, y_max, y_min;

    public RegionPosition(){
        this.x_max = 0;
        this.x_min = 0;
        this.y_max = 0;
        this.y_min = 0;
    }
    
    public void add(Pixel p){
        int x = p.getX();
        int y = p.getY();
        
        if(x > x_max) x_max = x;
        if(x < x_min) x_min = x;
        
        if(y > y_max) y_max = y;
        if(y < y_min) y_min = y;
    }
    
    @Override
    public String toString(){
        String res = "";
        res += "  x_max = " + x_max;
        res += ", x_min = " + x_min;
        res += ", y_max = " + y_max;
        res += ", y_min = " + y_min;
        return res;
    }
}

enum Bool{
    True,
    False,
    Nulled
};
